package other.her.system.erp;

import com.alibaba.fastjson.JSONObject;
import com.rkhd.platform.sdk.ScheduleJob;
import com.rkhd.platform.sdk.data.model.ARRECEIVEBILL__c;
import com.rkhd.platform.sdk.data.model.SyncConfig__c;
import com.rkhd.platform.sdk.exception.ScriptBusinessException;
import com.rkhd.platform.sdk.log.Logger;
import com.rkhd.platform.sdk.log.LoggerFactory;
import com.rkhd.platform.sdk.param.ScheduleJobParam;
import com.rkhd.platform.sdk.service.FutureTaskService;
import com.rkhd.platform.sdk.service.XoqlService;
import com.rkhd.platform.sdk.task.FutureTask;
import org.apache.commons.lang.StringUtils;
import other.her.system.client.ErpUtils;
import other.her.system.utils.HCXObjectService;
import other.her.system.utils.ResultVo;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 同步收款单
 * @Author 黎炎松
 * 2024-10-17 11:44
 */
public class SyncReceipt extends SyncSuper implements ScheduleJob, FutureTask {
    private static final Logger LOGGER = LoggerFactory.getLogger();
    private static final String LOGGER_MSG = "同步收款单数据到CRM ==> ";

    /**
     * 计划作业触发
     * @param scheduleJobParam
     */
    @Override
    public void execute(ScheduleJobParam scheduleJobParam) {
        LOGGER.info(LOGGER_MSG + "触发计划作业");
        try {
            String messageId = FutureTaskService.instance().addFutureTask(getClass(), "2");
            LOGGER.info(LOGGER_MSG + "异步ID:" + messageId);
        } catch (Exception e) {
            LOGGER.error(LOGGER_MSG + " ----- 发生异常：" + e.getMessage());
        }
    }

    /**
     *
     * @param type
     * @throws ScriptBusinessException
     */
    @Override
    public void execute(String type) {
        LOGGER.info(LOGGER_MSG + "触发异步同步");
        // 执行同步
        startSyncData(Integer.parseInt(type));
    }


    public static void main(String[] args) {
        SyncReceipt syncReceipt = new SyncReceipt();
        HCXObjectService.isLocal = true;
        syncReceipt.startSyncData(1);
    }

    /**
     * 开始同步不同账套ERP有变化的数据
     * @param type 1:首次批量处理 2：后续增量处理
     */
    public void startSyncData(int type) {
        // 获取同步配置里面的开始和结束时间
        SyncConfig__c syncConfig = getSyncConfig("ERP_SKD");;

        // 处理不同账套的数据
        for (Map<String, String> account : accountList) {
            if (type == 1) {
                initDataByAccount(account, syncConfig);
            } else {
                dealErpChangeDataByAccount(account);
            }
        }

        // 更新上次同步时间
        upSyncConfig(syncConfig);
    }

    /**
     * 增量处理ERP变化的数据
     */
    public void dealErpChangeDataByAccount(Map<String, String> account) {
        try {
            LOGGER.info(LOGGER_MSG + "开始处理新增、修改的数据: " + account.get("accountName"));

            // 查询ERP当前模块有变化的数据
            Map<String, String> module = moduleMap.get("skd");
            Map<String, String> idMap = getErpChangeData(module, account);
            if (idMap == null) {
                LOGGER.info("没有需要处理的数据");
                return;
            }

            // 新增、修改CRM数据
            String addUpIds = idMap.get("addUpIds");
            if (StringUtils.isNotBlank(addUpIds)) {
                String filterStr = String.format(" and t0.%s in (%s) ", module.get("idKey"), addUpIds);
                LOGGER.info(LOGGER_MSG + "filterStr: " + filterStr);
                ResultVo resultVo = syncErpReceipt(account, filterStr);
                if (resultVo.getCode() != 200) {
                    return;
                }
            }

            // 删除CRM数据 (根据账套 + 主表id删除数据)
            delCrmTableData("ARRECEIVEBILL__c", account.get("accountVal"), idMap.get("delIds"));

            // 需要把ERP处理完的记录表数据删除
            delErpRecordTable(idMap.get("erpTableIds"), account);

        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(account.get("accountName") + ": 增量处理ERP变化的数据 => " + e.getMessage());
        }
    }

    /**
     * 首次初始化数据 （没有创建时间、修改时间，使用自动排序进行分页查询）
     *
     * @param account
     * @param syncConfig
     */
    public void initDataByAccount(Map<String, String> account, SyncConfig__c syncConfig) {
        LOGGER.info(LOGGER_MSG + "开始初始化数据: " + account.get("accountName"));
        // 基础查询
        String baseSql = String.format("select ROW_NUMBER() over(order by FBillID) as num,FBillID from t_rp_NewReceiveBill " +
                " where FDate between '%s' and '%s'", syncConfig.getAttribute("startTime"), syncConfig.getAttribute("endTime"));

        // 获取当前模块的总数量
        String countSql = String.format("select count(*) as count from (%s) t", baseSql);
        JSONObject countObj = ErpUtils.queryOne(countSql, account.get("domain"));
        if (countObj == null) {
            LOGGER.error(LOGGER_MSG + "获取总数异常");
            return;
        }

        // 总数
        Integer tableCount = countObj.getInteger("count");
        LOGGER.info(LOGGER_MSG + "tableCount: " + tableCount);
        if (tableCount > 5000) {
            tableCount = 5000;
        }

        // 根据分页获取数据进行同步
        int startCount = 0;
        while (startCount < tableCount) {
            String filterSql = String.format(" and t0.FBillID in ( select FBillID from (%s) t where t.num between %d and %d ) ", baseSql, startCount, startCount += 100);
            LOGGER.info(LOGGER_MSG + "filterSql: " + filterSql);
            syncErpReceipt(account, filterSql);
        }

    }


    /**
     * 同步erp销售收款
     * @return
     */
    public ResultVo syncErpReceipt(Map<String, String> account, String filterStr) {
        try {
            LOGGER.info(LOGGER_MSG + "开始同步");
            int accountVal = Integer.parseInt(account.get("accountVal")); // CRM所属账套的值

            // 查询数据
            String erpSql = "select t0.FBillID,t0.FIndex,\n" +
                    "t1.FCustomer,t1.FNumber,t1.FSettle,t1.FExplanation,t1.FBillType,t1.FCurrencyID,t1.FExchangeRate,t1.FAmountFor,t1.FStatus,t1.FDate," +
                    "t1.FFincDate,t1.FEmployee,t1.FChecker,t0.FClassID_SRC,t0.FID_SRC,t0.FBillNo_SRC,t0.FOrderNo,t0.FItemid,t0.FQuantity,t0.FTaxPrice,t0.FAmountFor_SRC," +
                    "t0.FSettleAmountFor,t0.FSettleQuantity,t0.FRemainQty,t0.FRemainAmount,t0.FDiscountFor,\n" +
                    "org.FName as orgName,org.FNumber as orgNumber,emp.FName empName,buser.FName checkUserName,cp.FNumber as cpNumber,cu.Fname as cuName,enum.FName as billTypeName," +
                    "bt.FName as srcBillTypeName,se.FName as seName,t1.FClassTypeID,ct.FName as classTypeName \n" +
                    "from t_rp_ARBillOfSH t0 \n" +
                    "left join t_RP_NewReceiveBill t1 on t0.FBillID = t1.FBillID \n" +
                    "left join t_Organization org on t1.FCustomer = org.FItemID \n" +
                    "left join t_Base_Emp emp on t1.FEmployee = emp.FItemID \n" +
                    "left join t_Base_User buser on t1.FChecker = buser.FUserId \n" +
                    "left join t_ICItemCore cp on t0.FItemid = cp.FItemID \n" +
                    "left join t_Currency cu on t1.FCurrencyID = cu.FCurrencyID \n" +
                    "left join t_Settle se on t1.FSettle = se.FItemID \n" +
                    "left join t_RP_SystemEnum enum on t1.FBillType = enum.FItemID \n" +
                    "left join t_rp_BillType bt on t0.FClassID_SRC = bt.FID \n" +
                    "left join t_rp_BillType ct on t1.FClassTypeID = ct.FID \n" +
                    "where t1.FClassTypeID in (1000005,1000014,1000015) ";
            // 增加过滤条件
            if (StringUtils.isNotBlank(filterStr)) {
                erpSql += filterStr;
            }
            erpSql += " ORDER BY t0.FBillID ";

            List<JSONObject> erpDataList = ErpUtils.query(erpSql, account.get("domain"));
            LOGGER.info(LOGGER_MSG + "erpDataList: " + erpDataList.size());
            if (erpDataList == null || erpDataList.size() <= 0) {
                LOGGER.info(LOGGER_MSG + "查询异常或者没有需要同步的数据");
                return ResultVo.success();
            }

            // 根据ERP数据id查询CRM系统存在的数据 (明细标识：主表id + 明细序号)
            List<Long> crmRepeatIds =new ArrayList<>(); // 系统中重复的id
            String filterVals = erpDataList.stream().map(v -> "'" + v.getString("FBillID") + "'").collect(Collectors.joining(","));
            String sql = String.format("select id,ERPID__c,EntryID__c from ARRECEIVEBILL__c where zhangtao__c = %d and ERPID__c in (%s)", accountVal, filterVals);
            List<JSONObject> crmDataList = XoqlService.instance().query(sql).getRecords();
            Map<String, Long> crmDataMap = crmDataList.stream().collect(Collectors.toMap(e -> e.getString("EntryID__c"), e1 -> e1.getLong("id"), (e, e1) -> {
                crmRepeatIds.add(e1);
                return e;
            }));
            LOGGER.info(LOGGER_MSG + "crmDataMap: " + crmDataMap.size());

            // 获取CRM客户、用户、产品数据
            Map<String, Long> crmUserMap = getCrmDataMap("user", "empName", accountVal, erpDataList);
            Map<String, Long> crmAccountMap = getCrmDataMap("account", "orgNumber", accountVal, erpDataList);
            Map<String, Long> crmProductMap = getCrmDataMap("product", "cpNumber", accountVal, erpDataList);
            Map<String, Long> crmInvoiceMap = getCrmDataMap("saleInvoice", "FBillNo_SRC", accountVal, erpDataList);

            // 新增、修改数据
            HashSet<String> hasDealIds = new HashSet<>();
            List<ARRECEIVEBILL__c> crmAddList = new ArrayList<>();
            List<ARRECEIVEBILL__c> crmUpList = new ArrayList<>();
            for (JSONObject erpData : erpDataList) {
                // 唯一标识
                String entryId = erpData.getString("FBillID") + erpData.getString("FIndex");

                ARRECEIVEBILL__c receipt = new ARRECEIVEBILL__c();

                // 主表
                receipt.setERPID__c(erpData.getString("FBillID")); // 主表id
                receipt.setAccountName__c(crmAccountMap.get(erpData.getString("orgNumber"))); // 客户名称(关联关系-客户)
                receipt.setName(erpData.getString("FNumber")); // ERP收款单据号
                receipt.setFSettle__c(erpData.getString("seName")); // 结算方式
                receipt.setFExplanation__c(erpData.getString("FExplanation")); // 摘要
                receipt.setFBillType__c(erpData.getString("billTypeName")); // 收款类型
                receipt.setFClassType__c(erpData.getString("classTypeName")); // 事务类型
                receipt.setCurrencyUnit(1); // 币别 FCurrencyID
                receipt.setCurrencyRate(erpData.getDouble("FExchangeRate")); // 汇率
                receipt.setFAmountFor__c(erpData.getDouble("FAmountFor")); // 收款金额
                receipt.setFStatus__c(!Objects.equals(erpData.getInteger("FStatus"), 0) ? "Y" : "N"); // 状态 FStatus 不等于0都是Y
                receipt.setFDate__c(getDateVal(erpData.getString("FDate"))); // 单据日期
                receipt.setFFincDate__c(getDateVal(erpData.getString("FFincDate"))); // 财务日期

                // 业务员(关系关系-用户)
                Long ownerId = crmUserMap.get(erpData.getString("empName"));
                if (ownerId != null) {
                    receipt.setOwnerId(ownerId);
                }

                receipt.setFChecker__c(erpData.getString("checkUserName")); // 审核人

                // 子表
                receipt.setFClassID_SRC__c(erpData.getString("srcBillTypeName")); // 源单类型
                receipt.setFBillNoSRC__c(crmInvoiceMap.get(erpData.getString("FBillNo_SRC"))); // 源单编号（关联发票）
                receipt.setCustFOrderNo__c(erpData.getString("FOrderNo")); // 订单编号
                receipt.setProductName__c(crmProductMap.get(erpData.getString("cpNumber"))); // 产品编码(关联关系-产品)
                receipt.setFQuantity__c(erpData.getDouble("FQuantity")); // 数量
                receipt.setFTaxPrice__c(erpData.getDouble("FTaxPrice")); // 含税单价
                receipt.setFAmountForSRC__c(erpData.getDouble("FAmountFor_SRC")); // 选单单据金额
                receipt.setFSettleAmountFor__c(erpData.getDouble("FSettleAmountFor")); // 结算实收金额
                receipt.setFSettleQuantity__c(erpData.getDouble("FSettleQuantity")); // 结算数量
                receipt.setFRemainQty__c(erpData.getDouble("FRemainQty")); // 未核销数量
                receipt.setFRemainAmount__c(erpData.getDouble("FRemainAmount")); // 未核销金额
                receipt.setFDiscountFor__c(erpData.getDouble("FDiscountFor")); // 结算折扣金额

                if (crmDataMap.containsKey(entryId)) {
                    // 编辑
                    receipt.setId(crmDataMap.get(entryId));
                    crmUpList.add(receipt);
                } else {
                    // 新增
                    receipt.setEntityType(3510689401608846L); // 业务类型
                    receipt.setZhangtao__c(accountVal); // 所属账套
                    receipt.setEntryID__c(entryId); // 明细id
                    crmAddList.add(receipt);
                }

                // 批量新增、更新
                if (crmAddList.size() > 50) {
                    HCXObjectService.insertBatch(crmAddList);
                    crmAddList.clear();
                }
                if (crmUpList.size() > 50) {
                    HCXObjectService.updateBatch(crmUpList);
                    crmUpList.clear();
                }

                // 记录已经处理的id
                hasDealIds.add(entryId);
            }

            // 批量保存产品数据
            HCXObjectService.insertBatch(crmAddList);
            HCXObjectService.updateBatch(crmUpList);

            // 判断需要删除的数据（需要考虑ERP删除明细的情况）
            List<ARRECEIVEBILL__c> crmDelList = crmDataList.stream().filter(v -> !hasDealIds.contains(v.getString("EntryID__c"))).map(v -> {
                ARRECEIVEBILL__c receipt = new ARRECEIVEBILL__c();
                receipt.setId(v.getLong("id"));
                return receipt;
            }).collect(Collectors.toList());
            // 删除重复的数据
            List<ARRECEIVEBILL__c> repeatDelList = crmRepeatIds.stream().map(v -> {
                ARRECEIVEBILL__c receipt = new ARRECEIVEBILL__c();
                receipt.setId(v);
                return receipt;
            }).collect(Collectors.toList());
            crmDelList.addAll(repeatDelList);
            LOGGER.info(LOGGER_MSG + "需要删除的数据:" + crmDelList);
            HCXObjectService.deleteBatch(crmDelList);

            LOGGER.info(LOGGER_MSG + "同步结束");
            return ResultVo.success();
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("同步产品异常:" + e.getMessage());
            return ResultVo.error("同步产品异常:" + e.getMessage());
        }
    }


}
